package com.lxm.common.interceptor;

import cn.hutool.core.bean.BeanUtil;
import com.lxm.common.contants.LoginConstants;
import com.lxm.common.contants.UserConstants;
import com.lxm.common.tools.JwtUtils;
import com.lxm.common.tools.UserHolder;
import com.lxm.vo.LoginVO;
import io.jsonwebtoken.Claims;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.servlet.HandlerInterceptor;

import java.util.concurrent.TimeUnit;

import static com.lxm.common.contants.UserConstants.JWT_EXPIRE;


public class UserInterceptor implements HandlerInterceptor {

    private final JwtUtils jwtUtils;
    private final StringRedisTemplate stringRedisTemplate;

    public UserInterceptor(JwtUtils jwtUtils, StringRedisTemplate stringRedisTemplate) {
        this.jwtUtils = jwtUtils;
        this.stringRedisTemplate = stringRedisTemplate;
    }

    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response, Object handler) throws Exception {
        // 判断是否需要拦截,判断token
        String token = request.getHeader(LoginConstants.TOKEN_HEADER);
        String s = stringRedisTemplate.opsForValue().get(UserConstants.USER_TOKEN + token);
        if (s != null) {
            response.setStatus(401);
            return false;
        }
        //claims看了源码，可以看做Map子类的子类，根据子类能代表父类的规则，所以claims可以看做为Map
        //由于本身这个令牌的校验方式就是进行解密是否报错来确定，故而进行了二合一
        Claims claims = jwtUtils.validateAndParseToken(token);
        if (BeanUtil.isEmpty(claims)) {
            response.setStatus(401);
            return false;
        }
        LoginVO loginVO = BeanUtil.toBean(claims
                .get(LoginConstants.TOKEN_PREFIX), LoginVO.class);
        //废除旧的Token保证Token刷新且唯一有效
        String rightToken = stringRedisTemplate.opsForValue()
                .get(UserConstants.USER_TOKEN + loginVO.getUserId());
        if (!token.equals(rightToken)) {
            response.setStatus(401);
            return false;
        }
        // BeanUtil.fillBeanWithMap(claims, new LoginVO(), false);
        // 将可能需要用到的用户数据保存到ThreadLocal
        UserHolder.saveUser(loginVO);
        // 将新的Token添加到响应头中，让前端需要再去访问业务时，取出来重新装配Token
        String refreshToken = jwtUtils.refreshToken(token);
        response.setHeader(LoginConstants.TOKEN_HEADER, refreshToken);
        //存储Token
        stringRedisTemplate.opsForValue().set(UserConstants.USER_TOKEN + loginVO.getUserId(),
                refreshToken);
        stringRedisTemplate.expire(UserConstants.USER_TOKEN + loginVO.getUserId(),
                JWT_EXPIRE, TimeUnit.MINUTES);
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                                Object handler, Exception ex) throws Exception {
        UserHolder.removeUser();
    }
}
